package com.eian.boot.common.id;

import com.eian.boot.common.id.config.IdProperties;
import com.eian.boot.common.id.enums.IdStorageType;
import com.eian.boot.common.id.formatter.IdFormatter;
import com.eian.boot.common.id.generator.SnowflakeGenerator;
import com.eian.boot.common.id.generator.UuidGenerator;
import com.eian.boot.common.id.generator.segment.DbSegmentGenerator;
import com.eian.boot.common.id.generator.segment.RedisSegmentGenerator;
import com.eian.boot.common.id.generator.sequence.DbSequenceGenerator;
import com.eian.boot.common.id.generator.sequence.RedisSequenceGenerator;
import com.eian.boot.common.id.model.BatchIdConfig;
import com.eian.boot.common.id.model.PadPosition;
import com.eian.boot.common.id.obfuscator.IdObfuscator;
import com.eian.boot.common.id.service.BatchIdService;
import com.eian.boot.common.id.service.IdFormatService;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Set;

/**
 * 分布式ID生成器统一门面
 * 提供UUID、雪花ID、号段模式、序列号、自定义格式化等功能
 *
 * @author alex.meng
 */
@Component
@RequiredArgsConstructor
public class IdHelper {

    private static IdHelper instance;

    private final UuidGenerator uuidGenerator;
    private final SnowflakeGenerator snowflakeGenerator;
    private final IdFormatter idFormatter;
    private final IdObfuscator idObfuscator;
    private final IdProperties idProperties;

    @Autowired(required = false)
    private IdFormatService idFormatService;

    @Autowired(required = false)
    private BatchIdService batchIdService;

    @Autowired(required = false)
    private DbSegmentGenerator dbSegmentGenerator;

    @Autowired(required = false)
    private RedisSegmentGenerator redisSegmentGenerator;

    @Autowired(required = false)
    private DbSequenceGenerator dbSequenceGenerator;

    @Autowired(required = false)
    private RedisSequenceGenerator redisSequenceGenerator;

    /**
     * 获取时序UUID（带连字符）
     *
     * @return UUID字符串
     */
    public static String uuid() {
        return getInstance().uuidGenerator.uuid();
    }

    private static IdHelper getInstance() {
        if (instance == null) {
            throw new IllegalStateException("IdHelper未初始化，请确保Spring容器已启动");
        }
        return instance;
    }

    // ==================== 常规ID ====================

    /**
     * 获取下一个号段ID（根据配置自动选择DB或Redis）
     *
     * @param bizType 业务类型标识
     * @return 下一个ID
     */
    public static long nextSegmentId(String bizType) {
        IdHelper helper = getInstance();
        IdStorageType storageType = helper.idProperties.getSegmentStorageType();

        if (storageType == IdStorageType.DB) {
            return nextSegmentIdByDb(bizType);
        } else if (storageType == IdStorageType.REDIS) {
            return nextSegmentIdByRedis(bizType);
        } else {
            throw new IllegalStateException("未配置号段存储类型，请在配置文件中设置 eian.id.segment-storage-type");
        }
    }


    /**
     * 获取简化的UUID（无连字符）
     *
     * @return 简化后的UUID字符串
     */
    public static String simpleUuid() {
        return getInstance().uuidGenerator.simpleUuid();
    }

    /**
     * 获取雪花ID（long类型）
     *
     * @return 雪花ID
     */
    public static long snowflakeId() {
        return getInstance().snowflakeGenerator.snowflakeId();
    }

    /**
     * 获取雪花ID字符串形式
     *
     * @return 雪花ID字符串
     */
    public static String snowflakeIdStr() {
        return getInstance().snowflakeGenerator.snowflakeIdStr();
    }


    // ==================== 号段模式 ====================

    /**
     * 从数据库获取下一个号段ID
     *
     * @param bizType 业务类型标识
     * @return 下一个ID
     */
    public static long nextSegmentIdByDb(String bizType) {
        DbSegmentGenerator generator = getInstance().dbSegmentGenerator;
        if (generator == null) {
            throw new IllegalStateException("DB号段生成器未配置，请检查数据源配置");
        }
        return generator.nextId(bizType);
    }

    /**
     * 获取下一个序列号（根据配置自动选择DB或Redis）
     *
     * @param bizType 业务类型标识
     * @return 下一个序列号
     */
    public static long nextSequence(String bizType) {
        IdHelper helper = getInstance();
        IdStorageType storageType = helper.idProperties.getSequenceStorageType();

        if (storageType == IdStorageType.DB) {
            return nextSequenceByDb(bizType);
        } else if (storageType == IdStorageType.REDIS) {
            return nextSequenceByRedis(bizType);
        } else {
            throw new IllegalStateException("未配置序列号存储类型，请在配置文件中设置 eian.id.sequence-storage-type");
        }
    }

    /**
     * 从Redis获取下一个号段ID
     *
     * @param bizType 业务类型标识
     * @return 下一个ID
     */
    public static long nextSegmentIdByRedis(String bizType) {
        RedisSegmentGenerator generator = getInstance().redisSegmentGenerator;
        if (generator == null) {
            throw new IllegalStateException("Redis号段生成器未配置，请检查Redis配置");
        }
        return generator.nextId(bizType);
    }

    /**
     * 从数据库获取下一个序列号
     *
     * @param bizType 业务类型标识
     * @return 下一个序列号
     */
    public static long nextSequenceByDb(String bizType) {
        DbSequenceGenerator generator = getInstance().dbSequenceGenerator;
        if (generator == null) {
            throw new IllegalStateException("DB序列号生成器未配置，请检查数据源配置");
        }
        return generator.nextSequence(bizType);
    }


    // ==================== 顺序取号 ====================

    /**
     * 重置序列号（根据配置自动选择DB或Redis）
     *
     * @param bizType 业务类型标识
     */
    public static void resetSequence(String bizType) {
        IdHelper helper = getInstance();
        IdStorageType storageType = helper.idProperties.getSequenceStorageType();

        if (storageType == IdStorageType.DB) {
            resetSequenceByDb(bizType);
        } else if (storageType == IdStorageType.REDIS) {
            resetSequenceByRedis(bizType);
        } else {
            throw new IllegalStateException("未配置序列号存储类型，请在配置文件中设置 eian.id.sequence-storage-type");
        }
    }

    /**
     * 格式化ID（完整参数）
     *
     * @param rawId       原始ID
     * @param prefix      前缀
     * @param suffix      后缀
     * @param padChar     补位字符
     * @param length      总长度（不包括前后缀）
     * @param padPosition 补位位置
     * @return 格式化后的ID
     */
    public static String formatId(Object rawId, String prefix, String suffix, char padChar, int length, PadPosition padPosition) {
        return getInstance().idFormatter.formatId(rawId, prefix, suffix, padChar, length, padPosition);
    }

    /**
     * 从Redis获取下一个序列号
     *
     * @param bizType 业务类型标识
     * @return 下一个序列号
     */
    public static long nextSequenceByRedis(String bizType) {
        RedisSequenceGenerator generator = getInstance().redisSequenceGenerator;
        if (generator == null) {
            throw new IllegalStateException("Redis序列号生成器未配置，请检查Redis配置");
        }
        return generator.nextSequence(bizType);
    }

    /**
     * 重置数据库序列号
     *
     * @param bizType 业务类型标识
     */
    public static void resetSequenceByDb(String bizType) {
        DbSequenceGenerator generator = getInstance().dbSequenceGenerator;
        if (generator == null) {
            throw new IllegalStateException("DB序列号生成器未配置，请检查数据源配置");
        }
        generator.resetSequence(bizType);
    }

    /**
     * 重置Redis序列号
     *
     * @param bizType 业务类型标识
     */
    public static void resetSequenceByRedis(String bizType) {
        RedisSequenceGenerator generator = getInstance().redisSequenceGenerator;
        if (generator == null) {
            throw new IllegalStateException("Redis序列号生成器未配置，请检查Redis配置");
        }
        generator.resetSequence(bizType);
    }

    // ==================== 自定义格式化 ====================

    /**
     * 根据数据库配置生成完整ID（自动生成ID主体并格式化）
     * 根据id_format_config表配置自动生成ID内容、前缀、后缀等
     *
     * @param bizType 业务类型
     * @return 完整格式化的ID
     */
    public static String generateId(String bizType) {
        IdFormatService service = getInstance().idFormatService;
        if (service == null) {
            throw new IllegalStateException("ID格式化服务未配置，请检查数据源配置");
        }
        return service.generateIdByConfig(bizType);
    }

    /**
     * 根据数据库配置格式化ID（使用传入的原始ID）
     * 自动读取id_format_config表中的配置进行格式化
     *
     * @param bizType 业务类型
     * @param rawId   原始ID
     * @return 格式化后的ID
     */
    public static String formatIdByConfig(String bizType, long rawId) {
        IdFormatService service = getInstance().idFormatService;
        if (service == null) {
            throw new IllegalStateException("ID格式化服务未配置，请检查数据源配置");
        }
        return service.formatIdByConfig(bizType, rawId);
    }

    /**
     * 清除格式配置缓存
     *
     * @param bizType 业务类型，null表示清除所有
     */
    public static void clearFormatCache(String bizType) {
        IdFormatService service = getInstance().idFormatService;
        if (service != null) {
            service.clearCache(bizType);
        }
    }

    /**
     * 刷新格式配置缓存
     *
     * @param bizType 业务类型
     */
    public static void refreshFormatCache(String bizType) {
        IdFormatService service = getInstance().idFormatService;
        if (service != null) {
            service.refreshCache(bizType);
        }
    }

    /**
     * 格式化ID（使用默认补位字符'0'和左侧补位）
     *
     * @param rawId  原始ID
     * @param prefix 前缀
     * @param suffix 后缀
     * @param length 总长度
     * @return 格式化后的ID
     */
    public static String formatId(Object rawId, String prefix, String suffix, int length) {
        return getInstance().idFormatter.formatId(rawId, prefix, suffix, length);
    }

    /**
     * 格式化ID（使用默认补位字符和位置，无后缀）
     *
     * @param rawId  原始ID
     * @param prefix 前缀
     * @param length 总长度
     * @return 格式化后的ID
     */
    public static String formatId(Object rawId, String prefix, int length) {
        return getInstance().idFormatter.formatId(rawId, prefix, length);
    }

    /**
     * 格式化ID（仅前缀，不补位）
     *
     * @param rawId  原始ID
     * @param prefix 前缀
     * @return 格式化后的ID
     */
    public static String formatId(Object rawId, String prefix) {
        return getInstance().idFormatter.formatId(rawId, prefix);
    }

    /**
     * 格式化ID（仅补位，无前后缀）
     *
     * @param rawId  原始ID
     * @param length 总长度
     * @return 格式化后的ID
     */
    public static String formatId(Object rawId, int length) {
        return getInstance().idFormatter.formatId(rawId, length);
    }

    /**
     * 格式化ID（不做任何处理，仅转字符串）
     *
     * @param rawId 原始ID
     * @return 格式化后的ID
     */
    public static String formatId(Object rawId) {
        return getInstance().idFormatter.formatId(rawId);
    }

    /**
     * 混淆ID（用于订单号等需要弱可读性的场景）
     *
     * @param id 原始ID
     * @return 混淆后的ID
     */
    public static long obfuscateId(long id) {
        return getInstance().idObfuscator.obfuscate(id);
    }

    /**
     * 反混淆ID
     *
     * @param obfuscatedId 混淆后的ID
     * @return 原始ID
     */
    public static long deobfuscateId(long obfuscatedId) {
        return getInstance().idObfuscator.deobfuscate(obfuscatedId);
    }

    // ==================== 弱可读性（混淆） ====================

    /**
     * 混淆ID（字符串形式）
     *
     * @param id 原始ID
     * @return 混淆后的ID字符串
     */
    public static String obfuscateIdStr(long id) {
        return getInstance().idObfuscator.obfuscateStr(id);
    }

    /**
     * 反混淆ID（字符串形式）
     *
     * @param obfuscatedIdStr 混淆后的ID字符串
     * @return 原始ID
     */
    public static long deobfuscateIdStr(String obfuscatedIdStr) {
        return getInstance().idObfuscator.deobfuscateStr(obfuscatedIdStr);
    }

    /**
     * 基于数据库模板配置批量生成ID
     *
     * @param bizType 业务类型
     * @param count   生成数量
     * @return ID列表
     */
    public static List<String> generateBatch(String bizType, int count) {
        BatchIdService service = getInstance().batchIdService;
        if (service == null) {
            throw new IllegalStateException("批量ID生成服务未配置");
        }
        return service.generateBatch(bizType, count);
    }

    // ==================== 批量ID生成 ====================

    /**
     * 基于自定义配置批量生成ID
     *
     * @param config 自定义配置
     * @param count  生成数量
     * @return ID列表
     */
    public static List<String> generateBatch(BatchIdConfig config, int count) {
        BatchIdService service = getInstance().batchIdService;
        if (service == null) {
            throw new IllegalStateException("批量ID生成服务未配置");
        }
        return service.generateBatch(config, count);
    }

    /**
     * 基于数据库模板配置批量生成唯一ID（带去重）
     *
     * @param bizType 业务类型
     * @param count   生成数量
     * @return 唯一ID集合
     */
    public static Set<String> generateBatchUnique(String bizType, int count) {
        BatchIdService service = getInstance().batchIdService;
        if (service == null) {
            throw new IllegalStateException("批量ID生成服务未配置");
        }
        return service.generateBatchUnique(bizType, count);
    }

    /**
     * 基于数据库模板配置批量生成唯一ID（带去重和重试）
     *
     * @param bizType  业务类型
     * @param count    生成数量
     * @param maxRetry 最大重试次数
     * @return 唯一ID集合
     */
    public static Set<String> generateBatchUnique(String bizType, int count, int maxRetry) {
        BatchIdService service = getInstance().batchIdService;
        if (service == null) {
            throw new IllegalStateException("批量ID生成服务未配置");
        }
        return service.generateBatchUnique(bizType, count, maxRetry);
    }

    /**
     * 基于自定义配置批量生成唯一ID（带去重）
     *
     * @param config 自定义配置
     * @param count  生成数量
     * @return 唯一ID集合
     */
    public static Set<String> generateBatchUnique(BatchIdConfig config, int count) {
        BatchIdService service = getInstance().batchIdService;
        if (service == null) {
            throw new IllegalStateException("批量ID生成服务未配置");
        }
        return service.generateBatchUnique(config, count);
    }

    /**
     * 基于自定义配置批量生成唯一ID（带去重和重试）
     *
     * @param config   自定义配置
     * @param count    生成数量
     * @param maxRetry 最大重试次数
     * @return 唯一ID集合
     */
    public static Set<String> generateBatchUnique(BatchIdConfig config, int count, int maxRetry) {
        BatchIdService service = getInstance().batchIdService;
        if (service == null) {
            throw new IllegalStateException("批量ID生成服务未配置");
        }
        return service.generateBatchUnique(config, count, maxRetry);
    }

    @PostConstruct
    private void init() {
        instance = this;
    }
}

